package itsm.isperp.module.service.app;

import itsm.isperp.framework.core.context.ContextHolder;
import itsm.isperp.framework.quartz.domain.JobDefinition;
import itsm.isperp.framework.quartz.domain.JobParameter;
import itsm.isperp.framework.quartz.domain.JobState;
import itsm.isperp.framework.quartz.executor.SpringBeanJobExecutor;
import itsm.isperp.framework.quartz.executor.SpringBeanJobExecutorDetail;
import itsm.isperp.framework.quartz.service.IJobService;
import itsm.isperp.framework.service.BaseService;
import itsm.isperp.module.entity.app.AppJob;
import itsm.isperp.module.repository.app.AppJobMapper;
import itsm.isperp.module.repository.app.AppJobParameterMapper;

import java.text.ParseException;
import java.util.List;

import org.quartz.JobDataMap;
import org.quartz.JobDetail;
import org.quartz.JobKey;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.TriggerKey;
import org.quartz.impl.JobDetailImpl;
import org.quartz.impl.triggers.CronTriggerImpl;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Service;

/**
 * {@link JobDefinition}对象的基础服务.
 * <p>
 * 提供了大部分常用的功能,如调度,停止调度,查询,更新等.
 * </p>
 * 
 * 
 * @author lizx
 * @since 1.0
 */
@Service
public class AppJobService extends BaseService<AppJob> implements
		IJobService<AppJob>, ApplicationContextAware {
	public static final String JOB_PREFIX = "job";
	public static final String TRIGGER_PREFIX = "trigger";
	public static final String CALENDAR_PREFIX = "calendar";

	public static final String companyId = "isperp";

	protected ApplicationContext applicationContext;

	@Autowired
	protected AppJobSchedulerService appJobSchedulerService;

	@Autowired
	protected AppJobMapper appJobMapper;

	@Autowired
	protected AppJobParameterMapper appJobParameterMapper;

	@Override
	public AppJobMapper getRepository() {
		return this.appJobMapper;
	}

	@Override
	public void addJobToScheduler(JobDefinition jobDef)
			throws SchedulerException {
		addJobToScheduler(jobDef, null);
	}

	@Override
	public void addJobToScheduler(JobDefinition jobDef, JobDetailImpl jobDetail)
			throws SchedulerException {
		String jobDefId = jobDef.getId();
		Scheduler scheduler = appJobSchedulerService.retrieveScheduler();
		if (jobDetail == null) {
			jobDetail = new SpringBeanJobExecutorDetail(
					ContextHolder.getSpringBeanFactory(), jobDef.getBeanId());
		}
		if (jobDetail.getJobClass() == null) {
			jobDetail.setJobClass(SpringBeanJobExecutor.class);
		}
		jobDetail.setKey(new JobKey(JOB_PREFIX + jobDefId, companyId));
		jobDetail.setDescription(jobDef.getName() + ","
				+ jobDef.getDescription());
		JobDataMap jobDataMap = jobDetail.getJobDataMap();
		if (jobDataMap == null) {
			jobDataMap = new JobDataMap();
		}
		jobDataMap.put(IJobService.JOB_DEFINITION_ID, jobDefId);
		for (JobParameter p : appJobParameterMapper
				.getParametersByJobId(jobDefId)) {
			jobDataMap.put(p.getName(), p.getValue());
		}
		jobDetail.setJobDataMap(jobDataMap);
		CronTriggerImpl trigger = new CronTriggerImpl();
		try {
			trigger.setCronExpression(jobDef.getCronExpression());
		} catch (ParseException e1) {
			e1.printStackTrace();
			throw new SchedulerException(e1);
		}
		trigger.setName(TRIGGER_PREFIX + jobDefId);
		trigger.setGroup(companyId);
		try {
			trigger.setCronExpression(jobDef.getCronExpression());
		} catch (ParseException e) {
			e.printStackTrace();
			throw new SchedulerException(e);
		}
		JobKey jobKey = new JobKey(JOB_PREFIX + jobDefId, companyId);
		TriggerKey triggerKey = new TriggerKey(TRIGGER_PREFIX + jobDefId,
				companyId);
		if (scheduler.checkExists(jobKey)) {
			scheduler.pauseTrigger(triggerKey);
			scheduler.unscheduleJob(triggerKey);
			scheduler.deleteJob(jobKey);
		}

		scheduler.scheduleJob(jobDetail, trigger);
	}

	@Override
	public void removeJobFromScheduler(String jobDefId)
			throws SchedulerException {
		Scheduler scheduler = appJobSchedulerService.retrieveScheduler();
		JobKey jobKey = new JobKey(JOB_PREFIX + jobDefId, companyId);
		TriggerKey triggerKey = new TriggerKey(TRIGGER_PREFIX + jobDefId,
				companyId);
		if (scheduler.checkExists(jobKey)) {
			scheduler.pauseTrigger(triggerKey);
			scheduler.unscheduleJob(triggerKey);
			scheduler.deleteJob(jobKey);
		}
	}

	@Override
	public void resumeJob(String jobDefId) throws SchedulerException {
		Scheduler scheduler = appJobSchedulerService.retrieveScheduler();
		scheduler.resumeJob(new JobKey(JOB_PREFIX + jobDefId, companyId));
	}

	@Override
	public void pauseJob(String jobDefId) throws SchedulerException {
		Scheduler scheduler = appJobSchedulerService.retrieveScheduler();
		scheduler.pauseJob(new JobKey(JOB_PREFIX + jobDefId, companyId));
	}

	@Override
	public JobDetail getJobFromScheduler(String jobDefId)
			throws SchedulerException {
		Scheduler scheduler = appJobSchedulerService.retrieveScheduler();
		return scheduler.getJobDetail(new JobKey(JOB_PREFIX + jobDefId,
				companyId));
	}

	@Override
	public void updateTrigger(String jobDefId, String cronExpression)
			throws SchedulerException {
		Scheduler scheduler = appJobSchedulerService.retrieveScheduler();
		CronTriggerImpl trigger = (CronTriggerImpl) scheduler
				.getTrigger(new TriggerKey(TRIGGER_PREFIX + jobDefId, companyId));
		try {
			trigger.setCronExpression(cronExpression);
		} catch (ParseException e) {
			e.printStackTrace();
			throw new SchedulerException(e);
		}
		scheduler.scheduleJob(trigger);
	}

	@Override
	public List<AppJob> loadJobs(JobState state) {

		return appJobMapper.findAllByStatus(state.toString());
	}

	public void setApplicationContext(ApplicationContext applicationContext)
			throws BeansException {
		this.applicationContext = applicationContext;
	}

	@Override
	public void updateJob(AppJob jobDefinition) {

		this.saveOrUpdate(jobDefinition);
	}

	@Override
	public void updateJobStatus(String id, JobState status) {
		this.getRepository().updateJobStatus(id, status.toString());
	}
}
